/*
 * inotify-sync - a simple file synchronizer and file system watcher
 * Copyright (C) 2010-2011, inotify-sync developers and inotify-sync contributors
 * Copyright (C) 2010-2011, Cohesion Network Security Studio
 *
 * inotify-sync is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * inotify-sync is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with inotify-sync; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/*
 * FILE:		EventHandler.cpp
 * USAGE:		---
 * DESCRIPTION:		---
 * OPTIONS:		---
 * REQUIREMENTS:	---
 * BUGS:		---
 * NOTES:		---
 * AUTHOR:		LI Yiwei (mail:leeyiw@gmail.com)
 * COMPANY:		---
 * VERSION:		1.0
 * CREATED:		Wed Oct  5 13:09:12 CST 2011
 * REVISION:		---
 */

#include "EventHandler.h"

EventHandler::EventHandler(Profile& profile)
{
	this->profile=profile;
	switch(profile.get_log_mode())
	{
	case STD:
		p_logger=new StdLogger();
		break;
	case XML:
		p_logger=new XmlLogger(profile);
		break;
	}
	switch(profile.get_sync_mode())
	{
	case NSYNC:
		p_syncer=NULL;
		break;
	case RSYNC:
		p_syncer=new Syncer(profile);
		break;
	}
}

EventHandler::~EventHandler()
{
	delete p_logger;
	p_logger=0;
	delete p_syncer;
	p_syncer=0;
}

void
EventHandler::get_inotify(Inotify *p_inotify)
{
	this->p_inotify=p_inotify;
}

void
EventHandler::get_syncer(Syncer *p_syncer)
{
	this->p_syncer=p_syncer;
}

void
EventHandler::handle_events(vector<DirNode> *p_dnode_vec,
			vector<inotify_event *> *p_ievent_p_vec)
{
	for(size_t i=0;i<p_ievent_p_vec->size();i++)
	{
		inotify_event *p_ievent=p_ievent_p_vec->at(i);
		DirNode dnode;
		for(size_t j=0;j<p_dnode_vec->size();j++)
		{
			if(p_dnode_vec->at(j).wd==p_ievent->wd)
			{
				dnode=p_dnode_vec->at(j);
				break;
			}
		}
		string fname=dnode.abs_path;

		/*
		printf("wd:%d\n",p_ievent->wd);
		printf("mask:%x\n",p_ievent->mask);
		printf("cookie:%d\n",p_ievent->cookie);
		printf("name:%s\n",p_ievent->name);
		*/
		if(p_ievent->mask&IN_CREATE)
		{
			fname.append("/");
			fname.append(p_ievent->name);

			if(p_ievent->mask&IN_ISDIR)
			{
				p_inotify->init_dir(fname);
				p_logger->log_create(fname);
				if(p_syncer!=NULL)
					p_syncer->sync_create_dir(fname);
			}
			else
			{
				p_logger->log_create(fname);
				if(p_syncer!=NULL)
					p_syncer->sync_create_file(fname);
			}
		}
		if(p_ievent->mask&IN_DELETE)
		{
			fname.append("/");
			fname.append(p_ievent->name);

			if(p_ievent->mask&IN_ISDIR)
				p_inotify->destory_dir(fname);
			p_logger->log_delete(fname);
			if(p_syncer!=NULL)
				p_syncer->sync_delete(fname);
		}
		if(p_ievent->mask&IN_MODIFY)
		{
			fname.append("/");
			fname.append(p_ievent->name);

			p_logger->log_modify(fname);
			if(p_syncer!=NULL)
				p_syncer->sync_modify(fname);
		}
		if(p_ievent->mask&IN_MOVE_SELF)
		{
			for(size_t j=0;j<mevent_vec.size();j++)
			{
				if(mevent_vec[j].f_path==fname)
				{
					for(size_t k=0;k<p_dnode_vec->size();k++)
					{
						if(p_dnode_vec->at(k).abs_path==fname)
						{
							p_dnode_vec->at(k).abs_path=mevent_vec[j].t_path;
//规定：
//每次确认为内部移动时
//清空之前存在的MoveEvent
							mevent_vec.clear();
						}
					}
				}
			}
		}
		if(p_ievent->mask&IN_MOVED_FROM)
		{
			fname.append("/");
			fname.append(p_ievent->name);

			if(p_ievent->mask&IN_ISDIR)
				p_inotify->destory_dir(fname);
//每次捕捉到IN_MOVED_FROM时，都先将事件以MoveEvent容器存储，以便后续判定是否为内部移动
			MoveEvent mevent={p_ievent->cookie,fname,""};
			mevent_vec.push_back(mevent);

			p_logger->log_moved_from(fname,p_ievent->cookie);
			if(p_syncer!=NULL)
				p_syncer->sync_moved_from(fname,p_ievent->cookie);
		}
		if(p_ievent->mask&IN_MOVED_TO)
		{
			fname.append("/");
			fname.append(p_ievent->name);

			if(p_ievent->mask&IN_ISDIR)
				p_inotify->init_dir(fname);

			bool is_move_inside=false;
			for(size_t j=0;j<mevent_vec.size();j++)
			{
				//判断是否是监视目录内部移动并记录
				if(mevent_vec[j].cookie==p_ievent->cookie)
				{
					is_move_inside=true;
					mevent_vec[j].t_path=fname;
					p_logger->log_move_inside(mevent_vec[j].f_path,mevent_vec[j].t_path,mevent_vec[j].cookie);
					if(p_syncer!=NULL)
						p_syncer->sync_move_inside(fname,p_ievent->cookie);
					break;
				}
			}
			if(!is_move_inside)
			{
				p_logger->log_moved_to(fname,p_ievent->cookie);
				if(p_syncer!=NULL)
					p_syncer->sync_moved_to(fname);
			}
		}
	}
}
